import {
  Injectable,
  ConflictException,
  BadRequestException,
  NotFoundException,
  UnauthorizedException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { User } from '../user/entities/user.entity';

import { EmailService } from 'src/email/email.service';
import { AuthRegisterDto } from './dto/register-auth.dto';
import { encryptPassword, validatePassword } from 'src/utils/utils';
import { RedisService } from 'src/redis/redis.service';
import { AuthLoginDto } from './dto/login-auth.dto';
import { AuthLoginVo } from './vo/auth-login.vo';

@Injectable()
export class AuthService {
  constructor(
    private readonly emailService: EmailService,
    private readonly redisService: RedisService,
  ) {}

  @InjectRepository(User)
  private userRepository: Repository<User>;

  async sendEmail(email: string) {
    // 检测邮箱是否被注册
    const checkEmail = await this.checkEamilExists(email);
    if (checkEmail) return checkEmail;

    const code = await this.emailService.sendVerificationCode(email);
    console.log('code', code);
    return {
      code: 200,
      msg: '验证码发送成功',
    };
  }

  async register(user: AuthRegisterDto) {
    const savedCode = await this.redisService.getVerifyCode(user.email);
    if (!savedCode) {
      throw new BadRequestException('验证码已过期');
    }
    if (+savedCode !== user.captcha) {
      throw new BadRequestException('验证码不正确');
    }

    await this.redisService.del(`verify:${user.email}`);

    // 检查邮箱是否被注册
    const emailCheck = await this.checkEamilExists(user.email);
    if (emailCheck) return emailCheck;

    const { salt, hash } = encryptPassword(user.password); // 加密

    const newUser = this.userRepository.create({
      ...user,
      password: hash,
      salt: salt,
    });
    await this.userRepository.save(newUser);
    return {
      msg: '注册成功',
    };
  }

  async login(loginUser: AuthLoginDto) {
    const user = await this.userRepository.findOne({
      where: {
        username: loginUser.username,
      },
      select: [
        'id',
        'username',
        'nickname',
        'email',
        'isAdmin',
        'phone',
        'salt',
        'password',
        'createdAt',
        'avatar',
        'isFrozen',
      ],
      relations: ['roles', 'roles.permissions'],
    });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }
    const valid = validatePassword(
      loginUser.password,
      user.password,
      user.salt,
    );
    if (!valid) {
      throw new UnauthorizedException('密码不正确');
    }
    const vo = new AuthLoginVo();
    vo.userInfo = {
      id: user.id,
      username: user.username,
      nickname: user.nickname,
      email: user.email,
      avatar: user.avatar,
      phone: user.phone,
      createdAt: user.createdAt,
      isFrozen: user.isFrozen,
      isAdmin: user.isAdmin,
      roles: user.roles.map((role) => role.name),
      permissions: user.roles.reduce((permissions, role) => {
        return [...permissions, ...role.permissions];
      }, []),
    };
    return vo;
  }

  async findUserById(id: number) {
    const user = await this.userRepository.findOne({
      where: {
        id,
      },
      relations: ['roles', 'roles.permissions'],
    });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }
    return {
      id: user.id,
      username: user.username,
      roles: user.roles.map((item) => item.name),
      permissions: user.roles.reduce((permissions, role) => {
        return [...permissions, ...role.permissions];
      }, []),
    };
  }

  /**
   * 通过邮箱从user表查找user是否存在
   * @param email 邮箱
   * @returns null 未注册
   */
  private async checkEamilExists(email: string) {
    const existUser = await this.userRepository.findOne({
      where: { email },
    });
    if (existUser) {
      throw new ConflictException('邮箱已被注册');
    }
    return null; // 未注册
  }
}
